package showtime.framework.algorithm.qtree
{
	import flash.display.Graphics;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	/** 
	 * @project DelphiFrmework
	 * @author Delphi
	 * @date 2011-6-3
	 *
	 */
	
	public class QuadTreeNode
	{
		private var _rect:Rectangle = null;
		
		private var _NW:QuadTreeNode = null;
		
		private var _NE:QuadTreeNode = null;
		
		private var _SW:QuadTreeNode = null;
		
		private var _SE:QuadTreeNode = null;
		/**
		 * When parent = null, this node is root. 
		 */		
		private var _parent:QuadTreeNode = null;
		
		private var _childs:Array = null;
		private var _depth:int = 0;
		private var _numChilds:int = 0;
		private var _maxDepth:int = 0;
		
		/**
		 * Create a quadTreeNode object. 
		 * @param rect
		 * @param depth
		 * @param parent
		 * @param maxDepth
		 * 
		 */		
		public function QuadTreeNode(rect:Rectangle = null, depth:int = 0, parent:QuadTreeNode = null, maxDepth:int = 0)
		{
			_rect = rect;
			_depth = depth;
			_maxDepth = maxDepth;
			_parent = parent;
			_numChilds = 0;
			_childs = [];
		}
		
		public function draw(graphic:Graphics):void
		{
			graphic.lineStyle(1);
			
			graphic.drawRect(rect.x, rect.y, rect.width, rect.height);
			
			if (NW != null)
			{
				NW.draw(graphic);
				NE.draw(graphic);
				SW.draw(graphic);
				SE.draw(graphic);
			}
		}
		
		public function addChild(n:IQTObject):void
		{
			var go:Boolean = _depth + 1 > _maxDepth ? false : true;
			
			if (!go || _numChilds == 0) {
				_childs.push(n);
				_numChilds += 1;
				return;
			}
			
			// center of the rectangle.
			var c:Point = new Point(_rect.x + _rect.width / 2, _rect.y + _rect.height / 2);
			
			if (go) {
				// position(NW:8 NE:4 SW:6 SE:3).
				var p:int = (n.x > c.x ? 1 : 2) * (n.y > c.y ? 3 : 4);
				// create tree.
				if (_NW == null) {
					var w2:int = _rect.width / 2, h2:int = _rect.height / 2, d:int = _depth + 1;
					_NW = QuadTree.nodePool.getObject(QuadTreeNode);
					_NE = QuadTree.nodePool.getObject(QuadTreeNode);
					_SW = QuadTree.nodePool.getObject(QuadTreeNode);
					_SE = QuadTree.nodePool.getObject(QuadTreeNode);
					_NW.reset(new Rectangle(_rect.x, _rect.y, w2, h2), d, this, _maxDepth);
					_NE.reset(new Rectangle(_rect.x + w2, _rect.y, w2, h2), d, this, _maxDepth);
					_SW.reset(new Rectangle(_rect.x, _rect.y + h2, w2, h2), d, this, _maxDepth);
					_SE.reset(new Rectangle(_rect.x + w2, _rect.y + h2, w2, h2), d, this, _maxDepth);
				}
				
				switch(p) {
					case 8:
						_NW.addChild(n);
						break;
					case 4:
						_NE.addChild(n);
						break;
					case 6:
						_SW.addChild(n);
						break;
					case 3:
						_SE.addChild(n);
						break;
				}
				
				if (_childs.length > 0) {
					var obj:IQTObject = _childs.pop() as IQTObject;
					// position(NW:3 NE:4 SW:6 SE:8).
					var p0:int = (obj.x > c.x ? 1 : 2) * (obj.y > c.y ? 3 : 4);
					switch(p0) {
						case 8:
							_NW.addChild(obj);
							break;
						case 4:
							_NE.addChild(obj);
							break;
						case 6:
							_SW.addChild(obj);
							break;
						case 3:
							_SE.addChild(obj);
							break;
					}
				}
				
				_numChilds += 1;
			}
		}
		
		/**
		 * Reset Node.
		 * 
		 * @param	r Rectangle of the Node.
		 * @param	d Depth of the Node.
		 * @param	p Parent of the Node.
		 * @param	m Max depth of the Tree.
		 */
		public function reset(r:Rectangle = null, d:int = 0, p:QuadTreeNode = null, m:int = 0):void {
			if (_NE != null) {
				QuadTree.nodePool.returnObject(_NE, QuadTreeNode);
				QuadTree.nodePool.returnObject(_NW, QuadTreeNode);
				QuadTree.nodePool.returnObject(_SE, QuadTreeNode);
				QuadTree.nodePool.returnObject(_SW, QuadTreeNode);
				_NE.reset();
				_NW.reset();
				_SE.reset();
				_SW.reset();
				_NE = null;
				_NW = null;
				_SE = null;
				_SW = null;
			}
			_childs = new Array();
			_rect = r;
			_numChilds = 0;
			_depth = d;
			_maxDepth = m;
			_parent = p;
		}
		
		///////////////////////////////////
		// getter/setters
		///////////////////////////////////
		
		public function get NE():QuadTreeNode
		{
			return _NE;
		}
		
		public function get NW():QuadTreeNode
		{
			return _NW;
		}
		
		public function get SE():QuadTreeNode
		{
			return _SE;
		}
		
		public function get SW():QuadTreeNode
		{
			return _SW;
		}
		
		public function get numChilds():int
		{
			return _numChilds;
		}
		
		public function get depth():int
		{
			return _depth;
		}
		
		public function get childs():Array
		{
			return _childs;
		}
		
		public function get rect():Rectangle
		{
			return _rect;
		}
		
		public function get parent():QuadTreeNode
		{
			return _parent;
		}
		
		public function toString():String
		{
			return String(QuadTreeNode);
		}
	}
}